<?php

namespace app\service;

use app\exception\ErrnoPlus;
use app\model\UserDeviceBindingModel;
use app\service\cache\UserDeviceBindingCacheService;
use share\exception\ApiException;
use share\exception\Errno;
use share\service\AmqpService;
use share\service\BaseModelService;
use share\service\MQService;
use share\service\UserBaseService;
use share\utils\Helper;
use think\Log;

class UserDeviceBindingService extends BaseModelService
{

    public static function getModel()
    {
        return new UserDeviceBindingModel;
    }

    public static function getAllByUser($uid, $filter = [])
    {
        $filter['uid'] = $uid;
        return UserDeviceBindingCacheService::getAllByFilter($filter);
    }

    public static function getBindingInfoByIotId($iotId)
    {
        return self::getByFilter(['iot_id' => $iotId]);
    }

    public static function getBindingInfoByDeviceName($dn)
    {
        return self::getByFilter(['iot_id' => ['like', $dn . '%']]);
    }

    public static function getAllByIotId($iotIds)
    {
        if (count($iotIds) < 1) {
            return [];
        }
        $iotIds = Helper::arraySmartUnique($iotIds);
        return self::getAllByFilter([
            'iot_id' => ['in', $iotIds],
        ]);
    }

    public static function getAllByUserAndIotIds($uid, $iotIds)
    {
        if (count($iotIds) < 1) {
            return [];
        }
        $iotIds = Helper::arraySmartUnique($iotIds);
        return self::getAllByUser($uid, [
            'iot_id' => ['in', $iotIds],
        ]);
    }

    public static function del($id)
    {
        $origin = self::getBase($id);
        $res = UserDeviceBindingModel::destroy(['id' => $id]);
        if ($origin) {
            VirtualDeviceService::delMainDevice($origin['iot_id']);
            UserDeviceBindingCacheService::del(['uid' => $origin['uid']]);
        }
        return $res;
    }

    public static function deleteByUserIot($uid, $iotIds)
    {
        if (count($iotIds) < 1) {
            return [];
        }
        $iotIds = Helper::arraySmartUnique($iotIds);
        $res = UserDeviceBindingModel::destroy([
            'uid' => $uid,
            'iot_id' => ['in', $iotIds],
        ]);
        UserDeviceBindingCacheService::del(['uid' => $uid]);
        return $res;
    }

    public static function add($item)
    {
        parent::add($item);
        return UserDeviceBindingCacheService::del(['uid' => $item['uid']]);
    }

    public static function update($id, $item, $filter = [])
    {
        $origin = self::getBase($id);
        if($origin['uid']){
            UserDeviceBindingCacheService::del(['uid' => $origin['uid']]);
        }
        parent::update($id, $item, $filter);
        if (!isset($item['uid'])) {
            trace("update user bind  info but not set uid");
        } else {
            UserDeviceBindingCacheService::del(['uid' => $item['uid']]);
        }
    }


    /**
     * 用户绑定
     */
    public static function userBind($param,$vendor,$uid)
    {
        $serverSite = $param['serverSite'];
        if (!$serverSite) {
            $serverSite = "CN"; //默认阿里云站点为CN
        }
        $devices = $param['info'];
        if (count($devices) < 1) { //无设备信息
            return null;
        } 
        $iotIds = array_column($devices, 'iotId');
        $iotIds = Helper::arraySmartUnique($iotIds);
        $deviceInfos = DeviceInfoTableService::getAllByIotIds($iotIds);
        $bindInfo = self::getAllByIotId($iotIds);
        $tnMs = Helper::getMSTime();
        $tn = time();
        foreach($devices as $device){
            $deviceNewInfo = [
                'device_name' => $device['deviceName'],
                'iot_id' => $device['iotId'],
                'ch_num' => $device['chNum'],
                'server_site' => $serverSite,
                'vendor' => $vendor,
            ];
            DeviceInfoTableService::compareAndUpsert($deviceNewInfo, $deviceInfos);

            $originBindInfo = Helper::filterOne($bindInfo,['iot_id' => $device['iotId']]);
            if(empty($originBindInfo)){//绑定信息不存在
                $insert = [
                    "uid" => $uid, 
                    "iot_id" => $device["iotId"], 
                    "vendor" => $vendor, 
                    'firsttime' => $tn,
                    'modifytime' => $tn,
                    "amqptime" => $tnMs
                ];
                $update = [
                    "uid" => $uid, 
                    "vendor" => $vendor, 
                    'modifytime' => $tn,
                    "amqptime" => $tnMs
                ];
                // 真实情况 高并发时 这里直接add会冲突
                $ret = self::upsert($insert,$update);
                if($ret == 1){ // 新增
                    UserDeviceBindingCacheService::del(['uid' => $uid]);
                }
                else{ // 更新 或者未做出修改 删除缓存
                    UserDeviceBindingCacheService::delAll();
                }
            }
            else{
                // 用户不对应
                if ($originBindInfo['uid'] != $uid) {
                    //删除分享出去的设备信息
                    UserDeviceShareService::deleteByUserIot($originBindInfo['uid'], $device['iotId']);
                    UserDeviceBindingCacheService::del(['uid' => $uid]);
                    //更新绑定关系
                    self::update($originBindInfo['id'], [
                        "uid" => $uid,
                        "vendor" => $vendor,
                        "amqptime" => $tnMs
                    ]);
                }
            }
        }
        AmqpService::simplePush([
            'service' => 'app\\service\\AliyunProxyService@asyncUserBindInfo',
            'params' => [
                'uid' => $uid,
                "vendor" => $vendor,
            ],
        ]);

        // MQService::push([
        //     'service' => 'app\\service\\AliyunProxyService@asyncUserBindInfo',
        //     'params' => [
        //         'uid' => $uid,
        //         "vendor" => $vendor,
        //     ],
        // ], MQService::CHANNEL_OF_ACCOUNT);
    }

    /**
     * 更新设备信息
     */
    public static function changeBindInfo($param,$vendor)
    {
        $devices = $param['info'];
        if (count($devices) < 1) { //无设备信息
            return null;
        }
        $iotIds = array_column($devices, 'iotId');
        $iotIds = Helper::arraySmartUnique($iotIds);
        $deviceInfos = DeviceInfoTableService::getAllByIotIds($iotIds);
        foreach ($devices as $device) {
            $originDevice = Helper::filterOne($deviceInfos, ['iot_id' => $device['iotId']]);
            if (!empty($originDevice)) {
                //关键信息已变更
                if ($originDevice['ch_num'] != $device['chNum'] || $originDevice['vendor'] != $vendor) {
                    DeviceInfoTableService::update($originDevice['device_name'], [
                        'ch_num' => $device['chNum'],
                        'vendor' => $vendor,
                    ]);
                }
            }
        }
    }

    /**
     * 获取绑定用户信息
     */
    public static function getBindUserInfo($param,$vendor,$uid)
    {
        $dn = $param['deviceName'];
        AmqpService::simplePush([
            'service' => 'app\\service\\AliyunProxyService@asyncUserBindInfo',
            'params' => [
                'uid' => $uid,
                "vendor" => $vendor,
            ],
        ]);

        // MQService::push([
        //     'service' => 'app\\service\\AliyunProxyService@asyncUserBindInfo',
        //     'params' => [
        //         'uid' => $uid,
        //         "vendor" => $vendor,
        //     ],
        // ], MQService::CHANNEL_OF_ACCOUNT);

        $deviceInfo = DeviceInfoTableService::getBase($dn);
        if ($deviceInfo) {
            AmqpService::simplePush([
                'service' => 'app\\service\\AliyunProxyService@asyncDeviceBindInfoByIotId',
                'params' => [
                    'iotId' => $deviceInfo["iot_id"],
                    'region' => $deviceInfo["server_site"],
                    "vendor" => $vendor,
                ],
            ]);
            // MQService::push([
            //     'service' => 'app\\service\\AliyunProxyService@asyncDeviceBindInfoByIotId',
            //     'params' => [
            //         'iotId' => $deviceInfo["iot_id"],
            //         'region' => $deviceInfo["server_site"],
            //         "vendor" => $vendor,
            //     ],
            // ], MQService::CHANNEL_OF_ACCOUNT);
        }

        $bindInfo = self::getBindingInfoByDeviceName($dn);
 
        if (!$bindInfo) {
            throw new ApiException('the device is not exists ' . $dn, ErrnoPlus::DEVICE_NOT_BINDING);
        }
        $bindingUserInfo = UserBaseService::getBase($bindInfo['uid']);
        if (!$bindingUserInfo) {
            throw new ApiException("device {$dn} relation user is not exits", ErrnoPlus::USER_NOT_EXISTS);
        }
        $info = ["account" => "", "vendor" => 'ENZ'];
        if ($bindingUserInfo['vendor']) {
            $info["vendor"] = $bindingUserInfo['vendor'];
        }
        if ($bindingUserInfo['email']) {
            $info["account"] = $bindingUserInfo['email'];
        } elseif ($bindingUserInfo['phone']) {
            $info["account"] = $bindingUserInfo['phone'];
        }
        if (empty($info["account"])) {
            throw new ApiException('user info error', ErrnoPlus::COMMON_ERROR);
        }
        return $info;
    }

    /**
     * 查询设备是否被绑定
     */
    public static function isBind($param,$vendor)
    {
        $dn = $param['deviceName'];
        $deviceInfo = DeviceInfoTableService::getBase($dn);
        // 如果本地存在绑定关系  直接返回
        if (!empty($deviceInfo)) {
            $bindInfo = self::getBindingInfoByIotId($deviceInfo['iot_id']);
            if (!empty($bindInfo)) {
                return ['binding' => 1];
            }
        } else {
            AmqpService::simplePush([
                'service' => 'app\\service\\AliyunProxyService@asyncDeviceBindInfoByDeviceName',
                'params' => [
                    'deviceName' => $dn,
                    'productKey' => $param['productKey'],
                    'vendor' => $vendor,
                ],
            ]);
            // MQService::push([
            //     'service' => 'app\\service\\AliyunProxyService@asyncDeviceBindInfoByDeviceName',
            //     'params' => [
            //         'deviceName' => $dn,
            //         'productKey' => $param['productKey'],
            //         'vendor' => $vendor,
            //     ],
            // ], MQService::CHANNEL_OF_ACCOUNT);
        }
        return ['binding' => 0];
    }

    public static function isBindSimple($param,$vendor)
    {
        $dn = $param['deviceName'];
        $deviceInfo = DeviceInfoTableService::getBase($dn);
        // 如果本地存在绑定关系  直接返回
        if (!empty($deviceInfo)) {
            $bindInfo = self::getBindingInfoByIotId($deviceInfo['iot_id']);
            if (!empty($bindInfo)) {
                return ['binding' => 1];
            }
            AmqpService::simplePush([
                'service' => 'app\\service\\AliyunProxyService@asyncDeviceBindInfoByIotId',
                'params' => [
                    'iotId' => $deviceInfo['iot_id'],
                    'region' => $deviceInfo['server_site'],
                    'vendor' => $vendor,
                ],
            ]);
            // MQService::push([
            //     'service' => 'app\\service\\AliyunProxyService@asyncDeviceBindInfoByIotId',
            //     'params' => [
            //         'iotId' => $deviceInfo['iot_id'],
            //         'region' => $deviceInfo['server_site'],
            //         'vendor' => $vendor,
            //     ],
            // ], MQService::CHANNEL_OF_ACCOUNT);
        }
        return ['binding' => 0];
    }

    /**
     * 用户删除设备 (不是强制解绑)
     */
    public static function deleteBindDevice($param,$uid)
    {
        $iotIds = $param['info'];     
 
        $iotIds = Helper::arraySmartUnique($iotIds);

        if (count($iotIds) < 1) { //无设备信息
            return null;
        }
        if (empty($uid)) {
            throw new ApiException("call userBind but currentUser is null", Errno::COMMON_SYSTEM_ERROR);
        }
        // $bindingInfo = self::getAllByUserAndIotIds($uid, ["iot_id" => $iotIds]);
        // if (empty($bindingInfo)) {
        //     return null;
        //     //throw new ApiException("user " . $uid . " not binding given device");
        // }
        // $allowIotIds = Helper::arraySmartUnique(array_column($bindingInfo, 'iot_id'));

        UserDeviceShareService::deleteByUserIot($uid, $iotIds);
        DeviceGroupTableService::deleteByUserMainIds($uid, $iotIds);
        self::deleteByUserIot($uid, $iotIds);
    }

    /**
     * 解绑设备
     */
    public static function unbind($param)
    {
        $bindingInfo = self::getByFilter(["iot_id" => ["like", $param["deviceName"] . "%"]]);        
        if (!empty($bindingInfo)) {
            UserDeviceShareService::delByFilter(['main_id' => $bindingInfo['iot_id']]);
            self::del($bindingInfo['id']);
        }
    }

    /**
     * 解绑设备
     */
    public static function unbindByIotId($iotId){
        $bindingInfo = self::getByFilter(["iot_id" => $iotId]);    
        UserDeviceShareService::delByFilter(['iot_id' => $iotId ]);
        if (!empty($bindingInfo)) {
            self::del($bindingInfo['id']);
        }
    }

    /**
     * 设备换绑用户
     */
    public static function deviceChangeBindUser($iotId,$identityId){
        $originBind = self::getBindingInfoByIotId($iotId);
       
        $tnMs = Helper::getMSTime();
        $tn = time();
        $user = UserBaseService::getByFilter(['identity_id' => $identityId]);
        if(empty($user)){            
            trace("MQTT_bindChange: user of identity_id:".$identityId." not exist!",Log::ERROR);
            throw new ApiException("MQTT_bindChange: user of identity_id:".$identityId." not exist!",Errno::COMMON_SYSTEM_ERROR);
        }    
        if($originBind){//之前已存在 
            if($originBind['uid'] !== $user['id'] || $originBind['vendor'] !== $user['vendor']){
      
                self::update($originBind['id'],
                    [
                        "uid" => $user["id"], 
                        "vendor" => $user["vendor"],
                        'modifytime' => $tn,
                        "amqptime" => $tnMs
                    ]
                );
                // 换绑后删除之前的分享信息
                UserDeviceShareService::delByFilter(['iot_id' => $iotId]);

                // 删除之前的所有自定义设备信息
                VirtualDeviceService::delMainDevice($iotId);
            }
        }
        else{ //之前不存在的  直接删除相关信息
            $ret = self::upsert([
                "iot_id" => $iotId,
                "uid" => $user["id"], 
                "vendor" => $user["vendor"],
                'firsttime' => $tn,
                'modifytime' => $tn,
                "amqptime" => $tnMs
            ],[
                "uid" => $user["id"], 
                "vendor" => $user["vendor"],
                'modifytime' => $tn,
                "amqptime" => $tnMs
            ]);
            if($ret == 1){ // 新增
                UserDeviceBindingCacheService::del(['uid' => $user['id']]);
            }
            else{ // 更新 或者未做出修改 删除缓存
                UserDeviceBindingCacheService::delAll();
            }
            
            // 换绑后删除之前的分享信息
            UserDeviceShareService::delByFilter(['iot_id' => $iotId]);
            // 删除之前的所有自定义设备信息
            VirtualDeviceService::delMainDevice($iotId);
        }
    }

    public static function buildCondition($filter)
    {
        $res = [];
        if (isset($filter['userId']) && !empty($filter['userId'])) {
            $user = UserBaseService::getByUserId($filter['userId']);
            if($user){
                $res['uid'] = $user['id'];
            }            
        }
        if (isset($filter['iotId']) && !empty($filter['iotId'])) {
            $res['iot_id'] = $filter['iotId'];
        }
        return $res;
    }
}
